#include "cepollserverthread.h"
#include "cpublicdata.h"
#include "clogoper.h"
#include "cglobal.h"
#include "cclientdata.h"

#include <QHostAddress>

CEpollServerThread::CEpollServerThread() :
    QTcpThreadBase()
{
    m_nSockFd = -1;
    m_nEpfd = -1;
    m_bRunning = false;
    m_nReplyByte0 = CPublicData::instance().m_stServerCfg.m_nReplyByte0;
    m_nReplyByte1 = CPublicData::instance().m_stServerCfg.m_nReplyByte1;
}

CEpollServerThread::~CEpollServerThread()
{
    stopServer();
}

bool CEpollServerThread::startServer(int nPort)
{
    if (true == m_bRunning)
    {
        emit sigLogMsg(enAlarm, A2T("TCP服务端"), A2T("服务端已在运行"));
        return false;
    }
    if (nPort < 0 || nPort > 65535)
    {
        emit sigLogMsg(enAlarm, A2T("TCP服务端"), A2T("端口号错误, 端口号：%1").arg(nPort));
        return false;
    }

    m_nSockFd = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0);
    if (m_nSockFd < 0)
    {
        emit sigLogMsg(enAlarm, A2T("TCP服务端"), A2T("创建套接字失败，错误：%1").arg(m_nSockFd));
        return false;
    }

    //设置端口快速重新启用
    int nOpt = 1;
    int nRtn = setsockopt(m_nSockFd, SOL_SOCKET, SO_REUSEADDR, &nOpt, sizeof(nOpt));
    if (nRtn < 0)
    {
        emit sigLogMsg(enAlarm, A2T("TCP服务端"), A2T("设置套接字失败，错误：%1").arg(strerror(errno)));
        return false;
    }

    //socket配置
    struct sockaddr_in stAddr;
    memset(&stAddr, 0, sizeof(struct sockaddr_in));
    stAddr.sin_family = AF_INET;
    stAddr.sin_port = htons(nPort);
    stAddr.sin_addr.s_addr = INADDR_ANY;
    nRtn = bind(m_nSockFd, (struct sockaddr*)&stAddr, sizeof(struct sockaddr_in));
    if (nRtn < 0)
    {
        if (errno == EADDRINUSE)
        {
            emit sigLogMsg(enAlarm, A2T("TCP服务端"), A2T("端口 %1 已被占用，请确认该端口是否空闲或选择其他端口").arg(nPort));
        }
        else
        {
            emit sigLogMsg(enAlarm, A2T("TCP服务端"), A2T("绑定端口失败，错误：%1").arg(strerror(errno)));
        }
        return false;
    }

    nRtn = listen(m_nSockFd, 5);
    if (nRtn < 0)
    {
        emit sigLogMsg(enAlarm, A2T("TCP服务端"), A2T("监听端口失败，错误：%1").arg(strerror(errno)));
        return false;
    }

    //创建一个epoll
    m_nEpfd = epoll_create(1);
    if (m_nEpfd == -1)
    {
        emit sigLogMsg(enAlarm, A2T("TCP服务端"), A2T("创建epoll失败，错误：%1").arg(m_nEpfd));
        close(m_nSockFd);
        return false;
    }

    //储存epoll监听的IO事件
    struct epoll_event  stEvent;
    stEvent.events = EPOLLIN;
    stEvent.data.fd = m_nSockFd;
    //把socket交由epoll管理
    nRtn = epoll_ctl(m_nEpfd, EPOLL_CTL_ADD, m_nSockFd, &stEvent);
    if (nRtn < 0)
    {
        emit sigLogMsg(enAlarm, A2T("TCP服务端"), A2T("Epoll控制失败，错误：%1").arg(nRtn));
    }

    emit sigLogMsg(enWorkInfo, A2T("TCP服务端"), A2T("Tcp服务端启动成功"));
    m_bRunning = true;
    CPublicData::instance().m_bServerRuninng = true;
    startWorkThread(200);
    return true;
}

void CEpollServerThread::stopServer()
{
    if (false == m_bRunning)
    {
        emit sigLogMsg(enAlarm, A2T("TCP服务端"), A2T("Tcp服务端未运行"));
        return;
    }
    m_bRunning = false;
    stopWorkThread();

    if (m_nSockFd != -1)
    {
        shutdown(m_nSockFd, SHUT_RDWR);
        close(m_nSockFd);
        m_nSockFd = -1;
    }
    if (m_nEpfd != -1)
    {
        shutdown(m_nEpfd, SHUT_RDWR);
        close(m_nEpfd);
        m_nEpfd = -1;
    }
    while (m_vecClientFd.size() > 0)
    {
        int nFd = m_vecClientFd.first();
        shutdown(nFd, SHUT_RDWR);
        close(nFd);
        nFd = -1;
        m_vecClientFd.pop_front();
    }
    QList<CClientData*> listClient = CPublicData::instance().m_listClient;
    for (int i = 0; i < listClient.size(); i++)
    {
        listClient.at(i)->m_bState = false;
    }
    CPublicData::instance().m_bServerRuninng = false;
    emit sigLogMsg(enWorkInfo, A2T("TCP服务端"), A2T("Tcp服务端停止成功"));
}

bool CEpollServerThread::isRunning()
{
    return (bool)m_bRunning;
}

bool CEpollServerThread::sendRecvStatus(bool bRtn)
{
    char szBuffer[2];
    memset(szBuffer, 0, 2);
    szBuffer[0] = m_nReplyByte0;
    if (true == bRtn) szBuffer[0] = m_nReplyByte1;
    ssize_t nRtn = send(m_nSockFd, szBuffer, 1, MSG_DONTWAIT);
    if (nRtn == -1)
    {
        qDebug() << "send receive status fail:" << szBuffer[0];
    }
    return bRtn;
}

void CEpollServerThread::slotWorkProc()
{
    if (m_bStopWorkThread == true)  return;

    struct epoll_event  stEvents[DEF_EPOLL_SIZE];

    int nReady = epoll_wait(m_nEpfd, stEvents, DEF_EPOLL_SIZE, 1000);
    if (nReady == -1)
    {
        threadCirculate(100);
    }

    //依次处理IO时间 分别为sockfd和clientfd
    for (int i = 0; i < nReady; i++)
    {
        //触发sockfd，进行accept处理
        if (stEvents[i].data.fd == m_nSockFd)
        {
            struct sockaddr_in stClientAddr;
            memset(&stClientAddr, 0, sizeof(struct sockaddr_in));
            socklen_t nClientLen = sizeof(stClientAddr);

            //建立连接之后得到新的clientfd
            int nClientFd = accept(m_nSockFd, (struct sockaddr*)&stClientAddr, &nClientLen);
            if (nClientFd == -1)
            {
                if (errno == EAGAIN || errno == EWOULDBLOCK) break;
                emit sigLogMsg(enAlarm, A2T("TCP服务端"), A2T("accept 新客户端失败：") + QString(strerror(errno)));
                break;
            }

            //获取GUID判断是否配置该客户端
            QString sIp = QHostAddress(ntohl(stClientAddr.sin_addr.s_addr)).toString();
            if (false == CPublicData::instance().m_mapClient.contains(sIp))     //未配置
            {
                close(nClientFd);
                emit sigLogMsg(enAlarm, A2T("TCP服务端"), A2T("客户端 %1 未配置，已拒绝").arg(sIp));
                continue;
            }
            CClientData* pClient = CPublicData::instance().m_mapClient.value(sIp);
            if (false == pClient->m_bEnabled) //是否被停用
            {
                close(nClientFd);
                //emit sigLogMsg(enAlarm, A2T("TCP服务端"), A2T("客户端 %1 已停用，再次连接前请将状态设为启用").arg(sIp));
                continue;
            }
            if (true == pClient->m_bState)   //是否已连接
            {
                close(nClientFd);
                emit sigLogMsg(enAlarm, A2T("TCP服务端"), A2T("客户端 %1 已连接，禁止重复连接").arg(sIp));
                continue;
            }

            //确定事件的触发方式
            struct epoll_event stEvent;
            stEvent.events = EPOLLIN | EPOLLET;
            stEvent.data.fd = nClientFd;
            //clientfd交给epoll管理
            if (-1 == epoll_ctl(m_nEpfd, EPOLL_CTL_ADD, nClientFd, &stEvent))
            {
                close(nClientFd);
                emit sigLogMsg(enAlarm, A2T("TCP服务端"), A2T("Epoll control 新客户端失败：") + QString(strerror(errno)));
                continue;
            }
            m_vecClientFd.append(nClientFd);
            emit sigNewConnection(nClientFd, &stClientAddr);
        }
        //触发clientfd，进行读写操作
        else
        {
            int nClientFd = stEvents[i].data.fd;
            if (stEvents[i].events & (EPOLLERR | EPOLLHUP | EPOLLRDHUP))
            {
                emit sigConnectionClosed(nClientFd);
            }
            else
            {
                emit sigReadReady(nClientFd);
            }
        }
    }
    threadCirculate(100);
}
